use crate::handlers::{delete_markdown, get_markdown, get_markdown_titles, save_markdown};
use crate::models::DbState;
use crate::utils::{env_mongo_uri, initialize_mongo_client};
use actix_web::body::BoxBody;
use actix_web::dev::Service;
use actix_web::http::header::{self, HeaderValue}; // 正确导入 HeaderValue
use actix_web::{test, web, App};
use dotenvy::dotenv;
use serde_json::{to_vec, Value};
use std::str;

/// 初始化测试应用并返回服务实例
pub async fn setup_test_app() -> impl Service<
    actix_http::Request,
    Response = actix_web::dev::ServiceResponse<BoxBody>,
    Error = actix_web::Error,
> {
    dotenv().ok();
    let mongo_client = initialize_mongo_client(&env_mongo_uri()).await;
    test::init_service(
        App::new()
            .app_data(web::Data::new(DbState {
                client: mongo_client,
            }))
            .service(save_markdown)
            .service(get_markdown_titles)
            .service(delete_markdown)
            .service(get_markdown),
    )
    .await
}

/// 构建并发送请求，返回响应
pub async fn send_request(
    method: &str,
    uri: &str,
    payload: Option<Value>,
) -> actix_web::dev::ServiceResponse<BoxBody> {
    let mut app = setup_test_app().await;

    let req_builder = match method.to_lowercase().as_str() {
        "post" => test::TestRequest::post(),
        "get" => test::TestRequest::get(),
        "put" => test::TestRequest::put(),
        "delete" => test::TestRequest::delete(),
        _ => panic!("Unsupported HTTP method: {}", method),
    }
    .uri(uri)
    .insert_header((
        header::CONTENT_TYPE,
        HeaderValue::from_static("application/json"),
    ));

    let req = match payload {
        Some(payload) => req_builder
            .set_payload(to_vec(&payload).unwrap())
            .to_request(),
        None => req_builder.to_request(),
    };

    test::call_service(&mut app, req).await
}

/// 读取响应体并解析为JSON
pub async fn read_response_as_json(response: actix_web::dev::ServiceResponse<BoxBody>) -> Value {
    let body = test::read_body(response).await;
    let body_str = str::from_utf8(&body).expect("body to utf8 error");
    serde_json::from_str(body_str).expect("Failed to parse response as JSON")
}
